package com.fulihui.wgj.consumer.service.impl;


import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.fulihui.common.enums.CustomMsgTypeEnum;
import com.fulihui.common.enums.MsgTypeEnum;
import com.fulihui.common.util.JedisUtil;
import com.fulihui.common.util.PlatformUtil;
import com.fulihui.common.util.TemplateDisabledUtil;
import com.fulihui.common.util.TextMsgUtil;
import com.fulihui.open.weixin.enums.TemplateLogStatusEnum;
import com.fulihui.open.weixin.enums.TemplateStatusEnum;
import com.fulihui.weixinsdk.WeixinSDK;
import com.fulihui.weixinsdk.model.Material;
import com.fulihui.weixinsdk.model.MiniProgram;
import com.fulihui.weixinsdk.model.Mpnews;
import com.fulihui.weixinsdk.request.WeixinRequest;
import com.fulihui.weixinsdk.request.customer.CustomerImgMsgRequest;
import com.fulihui.weixinsdk.request.customer.CustomerMPNewsMsgRequest;
import com.fulihui.weixinsdk.request.customer.CustomerNewsMsgRequest;
import com.fulihui.weixinsdk.request.customer.CustomerTextMsgRequest;
import com.fulihui.weixinsdk.request.mass.MassSendRequest;
import com.fulihui.weixinsdk.request.template.TemplateSendRequest;
import com.fulihui.weixinsdk.result.WeixinResult;
import com.fulihui.weixinsdk.result.customer.CustomerNewsMsgResult;
import com.fulihui.weixinsdk.result.customer.CustomerTextMsgResult;
import com.fulihui.weixinsdk.result.mass.MassSendResult;
import com.fulihui.weixinsdk.result.template.TemplateSendResult;
import com.fulihui.weixinsdk.util.WxSDKErrorCode;
import com.fulihui.weixinsdk.util.WxSDKResultException;
import com.fulihui.wgj.consumer.entity.CustomerNewsMsg;
import com.fulihui.wgj.consumer.result.BatchSendResult;
import com.fulihui.wgj.consumer.service.UserService;
import com.fulihui.wgj.consumer.service.WxMsgService;
import com.fulihui.wgj.facade.dto.TemplateMsgDTO;
import com.fulihui.wgj.facade.dto.Wx48MsgDTO;
import com.fulihui.wgj.facade.msg.MassMsg;
import com.fulihui.wgj.facade.msg.Wx48HMsg;
import com.fulihui.wgj.facade.request.template.WxTemplateUpdateRequest;
import com.fulihui.wgj.facade.service.template.WxTemplateService;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * @author: LiuJie
 * @version: 2018/7/3 17:35
 * @description:
 */
@Service
@Slf4j
public class WxMsgServiceImpl implements WxMsgService {

    @Autowired
    private PlatformUtil platformUtil;
    @Autowired
    private JedisUtil jedisUtil;
    @Autowired
    private WeixinSDK weixinSDK;
    @Autowired
    private UserService userService;
    @Autowired
    private TemplateDisabledUtil templateDisabledUtil;
    @Reference(version = "1.0.0")
    private WxTemplateService wxTemplateService;

    /**
     * 回复文本消息
     *
     * @param appId      应用id
     * @param openId     openid
     * @param contentMsg 消息内容
     */
    @Override
    public void sendCustomerTextMsg(String appId, String openId, String contentMsg) {

        String info = "客服消息-文本消息 ";
        String accessToken = getAccessToken(appId, info);
        if (accessToken == null) {
            return;
        }

        CustomerTextMsgRequest request = new CustomerTextMsgRequest();
        request.setAccess_token(accessToken);
        request.setTouser(openId);
        request.setMsgtype(MsgTypeEnum.text.getCode());
        Map<String, String> content = Maps.newHashMap();
        //消息内容
        String escapeContnet = TextMsgUtil.escape(contentMsg);
        if (StringUtils.isBlank(escapeContnet)) {
            return;
        }
        content.put("content", escapeContnet);
        request.setText(content);
        //发送请求
        invokeWxService(info, request);

    }


    @Override
    public BatchSendResult sendCustomerNewsMsg(CustomerNewsMsg customerNewsMsg) {
        String appId = customerNewsMsg.getAppId();
        String info = "客服消息-自定义图文 ";
        String accessToken = getAccessToken(appId, info);
        if(null == accessToken){
            return null;
        }

       // 获取发送模板
        String subReplyNews = jedisUtil.get(customerNewsMsg.getNewsKey());
        if (StringUtils.isBlank(subReplyNews)) {
            return null;
        }

        Wx48MsgDTO wx48MsgDTO = JSON.parseObject(subReplyNews, Wx48MsgDTO.class);
        //推送
        List<String> openids = customerNewsMsg.getOpenIds();
        BatchSendResult result = new BatchSendResult();
        for (String openid : openids) {
            CustomerNewsMsgRequest newsMsgRequest = new CustomerNewsMsgRequest();
            newsMsgRequest.setAccess_token(accessToken);
            newsMsgRequest.setMsgtype(wx48MsgDTO.getMsgtype());
            newsMsgRequest.setNews(wx48MsgDTO.getNews());
            newsMsgRequest.setTouser(openid);
            try {
                if(invokeWxService(info,newsMsgRequest)){
                    result.successAddOne();
                }else {
                    result.failAddOne();
                }
            } catch (Exception e) {
                log.error(e.getMessage(),e);
                result.failAddOne();
            }
        }
        return result;
    }

    /**
     * 发送 客服 mpnews 消息
     *
     * @param appid
     * @param openId
     * @param mediaId 素材id
     */
    @Override
    public void sendConsumerMpNewsMsg(String appid, String openId, String mediaId) {
        sendMsgByMediaId(appid, openId, mediaId, CustomMsgTypeEnum.mpnews);
    }

    /**
     * 发送 客服 img 消息
     *
     * @param appid
     * @param openId
     * @param mediaId 素材id
     */
    @Override
    public void sendConsumerImgMsg(String appid, String openId, String mediaId) {
        sendMsgByMediaId(appid, openId, mediaId, CustomMsgTypeEnum.image);
    }

    /**
     * 发送模板消息
     *
     * @return 成功 or 失败
     */
    @Override
    public boolean sendTemplateMsg(String appid, String openid, TemplateMsgDTO templateMsgDTO) {
        String info = "模板消息发送";
        TemplateSendRequest request = new TemplateSendRequest();
        request.setAccess_token(getAccessToken(appid,info));
        request.setTouser(openid);

        String templateId = templateMsgDTO.getTemplateId();
        request.setTemplate_id(templateId);
        request.setUrl(templateMsgDTO.getTemplateUrl());
        request.setData(templateMsgDTO.getData());

        // 是否发送小程序
        if(null != templateMsgDTO.getMiniProgramAppId()
                && null != templateMsgDTO.getMiniProgramUrl()){
            MiniProgram miniprogram = new MiniProgram();
            miniprogram.setAppid(templateMsgDTO.getMiniProgramAppId());
            miniprogram.setPagepath(templateMsgDTO.getMiniProgramUrl());
            request.setMiniprogram(miniprogram);
        }

        try{
            WeixinResult res = weixinSDK.invokeService(request);
            if(res.isSuccess()){
                log.info(info+" 成功 ! request={}", request);
                return true;
            }else {
                // 应该不会走这里，SDK 里会检查，有问题的都抛异常出来了
                log.error(info+" 失败！response={}",res);
                return false;
            }
        }catch (WxSDKResultException e){
            if (e.getErrcode().contains(WxSDKErrorCode.UNSUBSCIRBE)) {
                // 删除取关 的用户信息
                log.error("{} 失败 用户取关！{}",info,request);
                userService.delUser(appid,openid);
                log.info("取关用户已删除！");
            }else if (e.getErrcode().contains(WxSDKErrorCode.TEMPLATE_DISABLED)) {
                //模板被封 往redis存储被封模板信息
                // 向redis 中存储失效模板
                templateDisabledUtil.addDisabledTemplate(templateId);
                // 更新数据库模板状态为无效
                WxTemplateUpdateRequest wxTemplateUpdateRequest = new WxTemplateUpdateRequest();
                wxTemplateUpdateRequest.setTemplateId(templateId);
                wxTemplateUpdateRequest.setStatus(TemplateStatusEnum.invalid.getValue());
                wxTemplateService.updateTemplateStatus(wxTemplateUpdateRequest);

                log.error("{} 失败 模板失效！{}",info,request);
            }else {
                log.error(info+" 失败！",e);
            }
            return false;
        }

    }

    /**
     * 群发消息
     *
     * @param msg
     */
    @Override
    public MassSendResult sendMassMsg(MassMsg msg) {
        final String info = "群发消息";

        List<String> openIds = msg.getOpenIds();
        if(CollectionUtils.isEmpty(openIds)){
            log.error("{} openId列表为空，取消发送。msg={}",info,msg);
            return null;
        }
        if(openIds.size() == 1){
            // 微信要求群发消息接口至少两条，
            // 不过这种假openid会被过滤，不会出现在 totalCount 里的
            openIds.add("MoNiOpenId");
        }

        MassSendRequest request = new MassSendRequest();
        request.setMsgtype(msg.getInfoType());

        String accessToken = getAccessToken(msg.getAppId(), info);
        if(StringUtils.isBlank(accessToken)){
            return null;
        }
        request.setAccess_token(accessToken);
        Mpnews mpnews = new Mpnews();
        mpnews.setMedia_id(msg.getMediaId());
        request.setMpnews(mpnews);
        request.setTouser(openIds);
        request.setSend_ignore_reprint(1);
        String uuid = UUID.randomUUID().toString().trim().replaceAll("-", "");
        request.setClientmsgid(uuid);
        return weixinSDK.invokeService(request);
    }

    /**
     * 客服接口发送 公众平台已有素材
     * @param appid
     * @param openId
     * @param mediaId
     * @param type
     */
    private void sendMsgByMediaId(String appid, String openId, String mediaId, CustomMsgTypeEnum type){
        if(StringUtils.isBlank(appid) || StringUtils.isBlank(openId) ||
                StringUtils.isBlank(mediaId) || null == type){
            log.error("发送客服消息失败，参数缺失。appid={},openid={},mediaid={},type={}",appid,openId,mediaId,type.getCode());
        }
        String info = "客服消息-类型=" + type.getCode();
        String accessToken = getAccessToken(appid, info);
        if(StringUtils.isBlank(accessToken)){
            return;
        }

        Material material = new Material();
        material.setMedia_id(mediaId);

        WeixinRequest request = null;
        switch (type){
            case image:
                CustomerImgMsgRequest img = new CustomerImgMsgRequest();
                img.setAccess_token(accessToken);
                img.setTouser(openId);
                img.setImage(material);
                request = img;
                break;
            case mpnews:
                CustomerMPNewsMsgRequest mpNews = new CustomerMPNewsMsgRequest();
                mpNews.setAccess_token(accessToken);
                mpNews.setTouser(openId);
                mpNews.setMpnews(material);
                request = mpNews;
                break;
            default:
        }
        if(null == request){
            log.error("Customer msg type undefined，type={}",type.getCode());
            return;
        }

        invokeWxService(info,request);
    }

    private String getAccessToken(String appId, String info) {
        String accessToken = platformUtil.get(appId);
        if (null == accessToken) {
            log.error("{} 获取 accessToken = null. appid = {}",info,appId);
        }
        return accessToken;
    }

    /**
     * 调用微信服务进行发送
     * 针对只需要判断成功或失败的
     * @param info
     * @param request
     */
    private boolean invokeWxService(String info, WeixinRequest request) {

        try{
            WeixinResult res = weixinSDK.invokeService(request);
            if(res.isSuccess()){
                log.info(info+" 成功 ! request={}", request);
                return true;
            }else {
                log.error(info+" 失败！tips={}",res);
                return false;
            }
        }catch (WxSDKResultException e){
            log.error(info+" 失败！",e);
            log.error("request={}",request);
            return false;
        }
    }
}
